package statistics;

import pac.KeyGen;
import datastructures.UserParameters;

public class SignificanceHelper extends AbstractStatisticTests {
	
	private static final int allOrders = 4;
	private static double[] p_cutoff = new double[allOrders];
	public static int[][] significanceListCases;
	
	static KeyGen keygen = new KeyGen(10000); 	
	
	private ExactTest exactTest;
	private IStatisticalTest asymptoticTest;
	
	private double MIN_CASES = 4;
	private double MIN_CONTROLS = 4;
	
	public SignificanceHelper ( String testName ) 
	{
		if ( testName.compareTo("D") == 0 ) 
			asymptoticTest = new D_Contrasts();
//		else if ( testName.compareTo("Dprime") == 0 ) //not working
//			asymptoticTest = new Dprime_Contrasts();
		else if ( testName.compareTo("R") == 0 ) 
			asymptoticTest = new R_Contrasts();
		else
			System.err.println("No such test. Using default R-contrast ... ");
		
		exactTest = new ExactTest(asymptoticTest);		
	}
	
	public void initializeBoundaryConditionsForExactTest ( int min_cases, int min_controls ) 
	{
		MIN_CASES = min_cases;
		MIN_CONTROLS = min_controls;
	}
	
	
	public double[] calculatePvalCutoffs (UserParameters userParams ) {
		p_cutoff = new double[allOrders];
		
		int denominator = 1; long numerator = 1; long combinations = 1;
		for(int order=1; order <= allOrders; order++) 
		{	
			/*
			 * Either the user has specified an over-riding threshold, or the default is Bonferroni.
			 */
			if( userParams.getSignificanceThreshold() != 1 )
				p_cutoff[order-1] = userParams.getSignificanceThreshold();			
			else 
			{
				denominator *= order;
				numerator *= (2*userParams.getNumber_of_snps() - order);
				combinations = numerator / denominator;
				p_cutoff[order-1] =  (double) 0.05 * userParams.getLenience() / combinations; 
			}			
		}
		
		return p_cutoff;
	}
	
	
	/*
	 * The idea is to have a more lenient case-only test than a case control test
	 */
	public double getCaseOnlyThreshold (int order) {
		double baseExponent = 1;  //used to be 0.8
		double pvalue = Math.pow ( p_cutoff[order-1], baseExponent);
		return pvalue;
	}
	
	public double getCaseControlThreshold(int order) {
		double pvalue = p_cutoff[order-1];
		return pvalue;
	}


	
	
//	private static volatile Map<Double, Double> caseObservationsToProbability = new ConcurrentHashMap<Double, Double>();
	public double TestCasesOnly ( int order, int[][][] observedCases ) 
	{	
//		int[] configuration = make1DArray(observedCases);
//		Double key = keygen.makeKey(configuration);
		
//		Double pValue = caseObservationsToProbability.get(key);			
//		 if ( pValue != null )
//			 return pValue;
		//else 
////		double pValue = statisticalTest.TestCasesOnly(order, observedCases);
		
//		caseObservationsToProbability.put(key,pValue);
////		return pValue;
		
		double probability = 1;
		double[][][] expectedCases = computeExpectations(observedCases);
		
		if( expectedCases[1][1][1] >= MIN_CASES ) 
			probability = asymptoticTest.TestCasesOnly ( order, observedCases );
//		else 
//			probability = exactTest.TestCasesOnly ( order, observedCases );	
				
		return probability;
	}
	
//	static static volatile Map<Double, Double> caseControlObservationsToProbability = new ConcurrentHashMap<Double, Double>();
	public double TestCasesVsControls ( int order, int[][][] observedCases, int[][][] observedControls ) 
	{ 
//		int[] case_configuration = make1DArray(observedCases);
//		int[] control_configuration = make1DArray(observedControls);
//		int[] case_control_configuration = new int[case_configuration.length + control_configuration.length];
//		System.arraycopy(case_configuration, 0, case_control_configuration, 0, case_configuration.length);
//		System.arraycopy(control_configuration, 0, case_control_configuration, case_configuration.length, control_configuration.length);
//		Double combinedKey = keygen.makeKey(case_control_configuration);
//		
//		Double pValue = caseControlObservationsToProbability.get(combinedKey);
//		if ( pValue != null )
//			return pValue;
		
////		Double pValue = statisticalTest.TestCasesVsControls(order, observedCases, observedControls);						
 //		caseControlObservationsToProbability.put(combinedKey, pValue);
		
////		return pValue;
		double probability = 1;
		double[][][] expectedCases = computeExpectations(observedCases);
		double[][][] expectedControls = computeExpectations(observedCases);
		
		if ( expectedCases[1][1][1] >= MIN_CASES && expectedControls[1][1][1] >= MIN_CONTROLS  ) 
			probability = asymptoticTest.TestCasesVsControls(order, observedCases, observedControls) ;
//		else
//			probability = exactTest.TestCasesVsControls(order, observedCases, observedControls) ;			
				
		return probability;
	}
	
	//for verbose more
	public double[] asymptoticAndExact_CaseOnly(int order, int[][][] observedCases) 
	{
		double[] bothPvalues = new double[2];
		bothPvalues[0] = asymptoticTest.TestCasesOnly ( order, observedCases );
		bothPvalues[1] = exactTest.TestCasesOnly ( order, observedCases );
		return bothPvalues;
	}
	
	public double[] asymptoticAndExact_CaseVsControl(int order, int[][][] observedCases, int[][][] observedControls) 
	{
		double[] bothPvalues = new double[2];
		bothPvalues[0] = asymptoticTest.TestCasesVsControls(order, observedCases, observedControls ) ;
		bothPvalues[1] = exactTest.TestCasesVsControls ( order, observedCases, observedControls ) ;
		return bothPvalues;
	}

}
